En el modelo los conductores deben tener percepciones del entorno de manera que les permita tomar decisiones.
Las situaciones pueden ser las siguientes:
Para cada situación descrita anteriormente se definen acciones que pueden realizar los conductores.
El auto continua con su velocidad actual.
El auto debe mantener una distancia de 3 metros entre sí mismo y el otro auto, por lo que aquí deberá reducir su velocidad de tal manera que no choque con él, o conservar su misma velocidad si está a una distancia adecuada.
Aquí se pueden desprender más situaciones dependiendo del color del semáforo:
El auto se debe detener (reducir velocidad a 0).
El auto debe ir reduciendo su velocidad.
El auto puede continuar moviéndose sin problemas y aumenta su velocidad.
import agentpy as ap
import numpy as np
import matplotlib.pyplot as plt
import json
import math
import random
import IPython
IPython.display.Image(url="./diagrama.jpeg")
class Semaphore(ap.Agent):
"""
Esta clase define a un semáforo.
"""
def setup(self):
""" Este método se utiliza para inicializar al semáforo. """
self.step_time = 0.1 # Tiempo que dura cada paso de la simulación
self.direction = [0, 1] # Dirección a la que apunta el semáforo
self.state = 2 # Estado del semáforo 0 = verde, 1 = amarillo, 2 = rojo
self.state_time = 0 # Tiempo que ha durado el semáforo en el estado actual
self.green_duration = 50 # Tiempo que dura el semáforo en verde
self.yellow_duration = 5 # Tiempo que dura el semáforo en amarillo
self.red_duration = 45 # Tiempo que dura el semáforo en rojo
self.cars_in_front = 0 # No. de carros frente al semaforo
self.on_time = 0 # Tiempo que ha durado el semáforo en verde
self.type = "" # tipo de semaforo (egoista, justo, random)
self.preference = [] # Orden de preferencias del semaforo
def update(self):
""" Este método actualiza el estado del semáforo. """
self.state_time += self.step_time
if self.state == 0:
# Caso en el que el semáforo está en verde
self.on_time += self.step_time
if self.state_time >= self.green_duration:
self.state = 1
self.state_time = 0
elif self.state == 1:
# Caso en el que el semáforo está en amarillo
if self.state_time >= self.yellow_duration:
self.state = 2
self.state_time = 0
# elif self.state == 2:
# # Caso en el que el semáforo está en rojo
# if self.state_time >= self.red_duration:
# self.state = 0
# self.state_time = 0
def set_green(self):
""" Este método forza el semáforo a estar en verde. """
self.state = 0
self.state_time = 0
def set_yellow(self):
""" Este método forza el semáforo a estar en amarillo. """
self.state = 1
self.state_time = 0
def set_red(self):
""" Este método forza el semáforo a estar en rojo. """
self.state = 2
self.state_time = 0
class Car(ap.Agent):
"""
Esta clase define a un auto.
"""
def setup(self):
""" Este método se utiliza para inicializar un robot limpiador. """
self.step_time = 0.1 # Tiempo que dura cada paso de la simulación
self.direction = [1, 0] # Dirección a la que viaja el auto
self.speed = 0.0 # Velocidad en metros por segundo
self.max_speed = 10 # Máxima velocidad en metros por segundo
self.state = 1 # Car state: 1 = ok, 0 = dead
def update_position(self):
""" Este método se utiliza para inicializar la posición del auto. """
# Verifica si el auto no ha chocado
if self.state == 0:
return
# Actualiza la posición según la velocidad actual
self.model.avenue.move_by(self, [self.speed*self.direction[0], self.speed*self.direction[1]])
def update_speed(self):
""" Este método se utiliza para inicializar la velocidad del auto. """
# Verifica si el auto no ha chocado
if self.state == 0:
return
# Obten la distancia más pequeña a uno de los autos que vaya en la misma dirección
p = self.model.avenue.positions[self]
min_car_distance = 1000000
for car in self.model.cars:
if car != self:
# Verifica si el carro va en la misma dirección
dot_p1 = np.dot(self.direction, car.direction)
# Verifica si el carro está atrás o adelante
p2 = self.model.avenue.positions[car]
dot_p2 = np.dot(np.array(
[[p2[0] - p[0]], [p2[1] - p[1]]]).T, self.direction)
if dot_p1 > 0 and dot_p2 > 0:
d = np.linalg.norm(p2 - p)
if min_car_distance > d:
min_car_distance = d
# Obten la distancia al próximo semáforo
min_semaphore_distance = 1000000
semaphore_state = -1
d1 = -1
d2 = -1
for semaphore in self.model.semaphores:
# Verifica si el semáforo apunta hacia el vehículo
dot_p1 = np.dot(semaphore.direction, self.direction)
# Verifica si el semáforo está adelante o atrás del vehículo
p2 = self.model.avenue.positions[semaphore]
dot_p2 = np.dot(np.array([[p2[0] - p[0]], [p2[1] - p[1]]]).T, self.direction)
# print(f'{semaphore.id} DP1: {dot_p1}, DP2: {dot_p2}')
if dot_p1 < 0 and dot_p2 > 0:
d = np.linalg.norm(p2 - p)
if min_semaphore_distance > d:
min_semaphore_distance = d
semaphore_state = semaphore.state
d1 = dot_p1
d2 = dot_p2
# print("MIN S D: ", min_semaphore_distance)
# print( f'd1: {d1}, d2: {d2}, state: {semaphore_state}')
# Actualiza la velocidad del auto
if min_car_distance < 2:
self.speed = 0
self.state = 1
elif min_car_distance <= 20:
self.speed = np.maximum(self.speed - 200*self.step_time, 0)
elif min_car_distance <= 50:
self.speed = np.maximum(self.speed - 80*self.step_time, 0)
elif min_semaphore_distance < 20 and semaphore_state == 1:
self.speed = np.minimum(self.speed + 5*self.step_time, self.max_speed)
elif min_semaphore_distance < 50 and semaphore_state == 1:
self.speed = np.maximum(self.speed - 5*self.step_time, 0)
# hay un alto
elif min_semaphore_distance <= 20 and semaphore_state == 2:
self.speed = np.maximum(self.speed - 3000 * self.step_time, 0)
# hay un alto a lo lejos
elif min_semaphore_distance < 100 and semaphore_state == 2:
self.speed = np.maximum(self.speed - 500 * self.step_time, 0)
else:
self.speed = np.minimum(self.speed + 5*self.step_time, self.max_speed)
# elif min_car_distance <= 5:
# self.speed = np.maximum(self.speed - 200*self.step_time, 0)
# elif min_car_distance <= 15:
# self.speed = np.maximum(self.speed - 80*self.step_time, 0)
# elif min_semaphore_distance < 10 and semaphore_state == 1:
# self.speed = np.minimum(self.speed + 5*self.step_time, self.max_speed)
# elif min_semaphore_distance < 35 and semaphore_state == 1:
# self.speed = np.maximum(self.speed - 5*self.step_time, 0)
# # hay un alto
# elif min_semaphore_distance <= 10 and semaphore_state == 2:
# self.speed = np.maximum(self.speed - 3000 * self.step_time, 0)
# # hay un alto a lo lejos
# elif min_semaphore_distance < 35 and semaphore_state == 2:
# self.speed = np.maximum(self.speed - 500 * self.step_time, 0)
# else:
# self.speed = np.minimum(self.speed + 5*self.step_time, self.max_speed)
class AvenueModel(ap.Model):
""" Esta clase define un modelo para una avenida simple con semáforo peatonal. """
def setup(self):
""" Este método se utiliza para inicializar la avenida con varios autos y semáforos. """
# Inicializa los agentes los autos y los semáforos
self.cars = ap.AgentList(self, self.p.cars, Car)
self.cars.step_time = self.p.step_time
self.cars_red = 0
self.avg_speed = []
global info
info = {'cars':[], 'frames': []}
self.frame_counter = 0
car_counter = self.p.cars
c_north = int(self.p.cars/4)
car_counter -= c_north
c_south = int(self.p.cars/2 - c_north)
car_counter -= c_south
c_east = int (car_counter/2)
car_counter -= c_north
c_west = car_counter
car_counter -= c_west
# print(f'DISTRIB: {c_north}, {c_south}, {c_east}, {c_west}')
for k in range(c_north):
self.cars[k].direction = [0,1]
for k in range(c_south):
self.cars[k + c_north].direction = [0,-1]
for k in range(c_east):
self.cars[k + c_north + c_south].direction = [1,0]
for k in range(c_west):
self.cars[k + c_north + c_south + c_east].direction = [-1,0]
self.semaphores = ap.AgentList(self,4, Semaphore)
self.semaphores.step_time = self.p.step_time
self.semaphores.green_duration = self.p.green
self.semaphores.yellow_duration = self.p.yellow
self.semaphores.red_duration = self.p.red
self.semaphores[0].direction = [0, 1] #Norte
self.semaphores[1].direction = [0, -1] #Sur
self.semaphores[2].direction = [1, 0] #Este
self.semaphores[3].direction = [-1, 0] #Oeste
# self.semaphores.state = ap.AttrIter([0, 0, 2, 2])
# Inicializa el entorno
self.avenue = ap.Space(self, shape=[self.p.size, self.p.size], torus = True)
# Agrega los semáforos al entorno
self.avenue.add_agents(self.semaphores, random=True)
self.avenue.move_to(self.semaphores[0], [400, self.p.size*0.5 + 50])
self.avenue.move_to(self.semaphores[1], [600, self.p.size*0.5 - 50])
self.avenue.move_to(self.semaphores[2], [600, self.p.size*0.5 + 50])
self.avenue.move_to(self.semaphores[3], [400, self.p.size*0.5 - 50])
# self.avenue.move_to(self.semaphores[0], [self.p.size*0.5 - 10, self.p.size*0.5 + 10])
# self.avenue.move_to(self.semaphores[1], [self.p.size*0.5 + 10, self.p.size*0.5 - 10])
# self.avenue.move_to(self.semaphores[2], [self.p.size*0.5 + 10, self.p.size*0.5 + 10])
# self.avenue.move_to(self.semaphores[3], [self.p.size*0.5 - 10, self.p.size*0.5 + 10])
# Define los tipos de cada semaforo
self.semaphores[0].type = "selfish"
self.semaphores[1].type = "fair"
self.semaphores[2].type = "random"
self.semaphores[3].type = "random"
# Agrega los autos al entorno
self.avenue.add_agents(self.cars, random=True)
for k in range(c_north):
self.avenue.move_to(self.cars[k], [570, 10*(k+1)])
for k in range(c_south):
self.avenue.move_to(self.cars[k+c_north], [430, self.p.size - (k+1)*10])
for k in range(c_east):
self.avenue.move_to(self.cars[k + c_north + c_south], [10*(k+1), 470])
for k in range(c_west):
self.avenue.move_to(self.cars[k + c_north + c_south + c_east],
[self.p.size - (k+1)*10, 520])
for car in self.cars:
init_info = {
'id': car.id - 1,
'x': self.avenue.positions[car][0],
'z': self.avenue.positions[car][1], #Convertir y del modelo a z en la simulacion
'direction': (180 if car.direction[1] > 0 else 0) if car.direction[0] == 0 else (90 if car.direction[0] > 0 else 270)
}
info['cars'].append(init_info)
def step(self):
""" Este método se invoca para actualizar el estado de la avenida. """
self.semaphores.update()
if(self.semaphores[0].state == 2 and
self.semaphores[1].state == 2 and
self.semaphores[2].state == 2 and
self.semaphores[3].state == 2):
votes = self.propose()
winner = self.vote(votes)
print(f'WINNER: { winner }, TIME ON: { self.semaphores[winner].on_time }')
self.semaphores[winner].set_green()
print(f'[{self.semaphores[0].state}, {self.semaphores[1].state}, {self.semaphores[2].state}, {self.semaphores[3].state}]')
# for i in range(4):
# if i != winner:
# self.semaphores[i].state = 2
self.cars.update_position()
self.cars.update_speed()
if (self.t * self.p.step_time) >= (self.p.steps * self.p.step_time):
self.stop()
def update(self):
avg_speed = []
n_cars = 0
for car in self.cars:
# dot_prod1 = np.dot(car.direction, self.semaphores[0].direction)
# dot_prod2 = np.dot(car.direction, self.semaphores[1].direction)
dist1 = np.linalg.norm(self.avenue.positions[self.semaphores[0]] - self.avenue.positions[car])
dist2 = np.linalg.norm(self.avenue.positions[self.semaphores[1]] - self.avenue.positions[car])
dist3 = np.linalg.norm(self.avenue.positions[self.semaphores[2]] - self.avenue.positions[car])
dist4 = np.linalg.norm(self.avenue.positions[self.semaphores[3]] - self.avenue.positions[car])
if dist1 <= 200 or dist2 <= 200 or dist3 <= 200 or dist4 <= 200:
avg_speed.append(car.speed)
if self.semaphores[0].state == 2 and self.semaphores[1].state == 2 and self.semaphores[2].state == 2 and self.semaphores[3].state == 2:
n_cars += 1
avg_speed = np.average(avg_speed)
if np.isnan(avg_speed):
avg_speed = 0
self.record('Avg Speed', avg_speed)
self.record('Cars_red_light', n_cars)
self.cars_red = n_cars
self.avg_speed.append(avg_speed)
frame_info = {
'frame': self.frame_counter,
'cars': [
{
'id': car.id - 1,
'x': (5 if self.avenue.positions[car][0] <= 430 else -5) if (car.direction[0] == 0) else (self.avenue.positions[car][0] - 500 if car.direction[0] > 0 else self.avenue.positions[car][0] - 650),
'z': (self.avenue.positions[car][1] - 450) if car.direction[0] == 0 else (70 if car.direction[0] > 0 else 25), #Convertir y del modelo a z en la simulacion
# 'dir': 180 if car.direction[1] > 0 else 0
'dir': (180 if car.direction[1] > 0 else 0) if car.direction[0] == 0 else (270 if car.direction[0] > 0 else 90)
} for car in self.cars
]
}
# frame_info = {
# 'frame': self.frame_counter,
# 'cars': [
# {
# 'id': car.id - 1,
# 'x': self.avenue.positions[car][0],
# 'z': self.avenue.positions[car][1],
# 'dir': (180 if car.direction[1] > 0 else 0) if car.direction[0] == 0 else (90 if car.direction[0] > 0 else 270)
# } for car in self.cars
# ]
# }
info['frames'].append(frame_info)
self.frame_counter += 1
def propose(self):
proposals = []
for semaphore in self.semaphores:
semaphore_order = []
myset = set()
cont = 0
while cont < len(self.semaphores):
nextInt = random.randint(1,4)
if nextInt not in myset:
semaphore_order.append(nextInt)
myset.add(nextInt)
cont += 1
# if(semaphore.type == "selfish"):
# semaphore_order.append(semaphore.id - 10)
# my_order_dict = {}
# for other in self.semaphores:
# if(other.id != semaphore.id):
# my_order_dict[other.id - 10] = other.on_time
# to_list = sorted(my_order_dict.items(), key=lambda x:x[1], reverse=True)
# sorted_order = dict(to_list)
# for x in sorted_order.keys():
# semaphore_order.append(x)
# elif(semaphore.type == "fair"):
# my_order_dict = {}
# for s in self.semaphores:
# my_order_dict[s.id - 10] = s.on_time
# to_list = sorted(my_order_dict.items(), key=lambda x:x[1], reverse=True)
# sorted_order = dict(to_list)
# for x in sorted_order.keys():
# semaphore_order.append(x)
# else: #Random
# myset = set()
# cont = 0
# while cont < len(self.semaphores):
# nextInt = random.randint(1,4)
# if nextInt not in myset:
# semaphore_order.append(nextInt)
# myset.add(nextInt)
# cont += 1
proposals.append(semaphore_order)
# print("PROPOSALS: ", proposals)
return proposals
def vote(self, votes):
num_answers = len(votes)
num_options = len(votes[0])
final_votes = [0] * num_options
for i in range(num_options):
votes_per_option = 0
for j in range(num_answers):
if votes[j][i] == 1:
votes_per_option = votes_per_option + 1
final_votes[i] = votes_per_option
max_value = max(final_votes)
max_index = final_votes.index(max_value)
return max_index
def end(self):
avg_speed = np.average(self.cars.speed)
self.report('Avg Speed', self.avg_speed)
self.report('Cars in red light', self.cars_red)
self.report('Time', self.t * 2)
# print(type(info['frames']))
# print("\n info \n", info)
json_string = json.dumps(info, indent=4)
with open("data.json", "w") as file:
file.write(json_string)
def animation_plot_single(m, ax):
ax.set_title(f"Avenida t={m.t*m.p.step_time:.2f}")
colors = ["green", "yellow", "red"]
pos_s1 = m.avenue.positions[m.semaphores[0]]
ax.scatter(*pos_s1, s=20, c=colors[m.semaphores[0].state])
pos_s2 = m.avenue.positions[m.semaphores[1]]
ax.scatter(*pos_s2, s=20, c=colors[m.semaphores[1].state])
pos_s3 = m.avenue.positions[m.semaphores[2]]
ax.scatter(*pos_s3, s=20, c=colors[m.semaphores[2].state])
pos_s4 = m.avenue.positions[m.semaphores[3]]
ax.scatter(*pos_s4, s=20, c=colors[m.semaphores[3].state])
ax.set_xlim(0, m.avenue.shape[0])
ax.set_ylim(0, m.avenue.shape[1])
for car in m.cars:
pos_c = m.avenue.positions[car]
ax.scatter(*pos_c, s=20, c="black")
ax.set_axis_off()
ax.set_aspect('equal', 'box')
def animation_plot(m, p):
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111)
animation = ap.animate(m(p), fig, ax, animation_plot_single)
return IPython.display.HTML(animation.to_jshtml(fps=20))
parameters = {
'step_time': 0.1, # Tiempo por cada frame de simulación
'size': 1000, # Tamaño en metros de la avenida
'green': 10, # Duración de la luz verde
'yellow': 5, # Duración de la luz amarilla
'red': 10, # Duración de la luz roja
'cars': 20, # Número de autos en la simulación
'steps': 1000, # Número de pasos de la simulación
}
model = AvenueModel(parameters)
results = model.run()
# results.arrange_variables()
WINNER: 0, TIME ON: 0 [0, 2, 2, 2] Completed: 152 stepsWINNER: 0, TIME ON: 10.09999999999998 [0, 2, 2, 2] Completed: 304 stepsWINNER: 3, TIME ON: 0 [2, 2, 2, 0] Completed: 456 stepsWINNER: 0, TIME ON: 20.200000000000017 [0, 2, 2, 2] Completed: 608 stepsWINNER: 3, TIME ON: 10.09999999999998 [2, 2, 2, 0] Completed: 760 stepsWINNER: 2, TIME ON: 0 [2, 2, 0, 2] Completed: 912 stepsWINNER: 2, TIME ON: 10.09999999999998 [2, 2, 0, 2] Completed: 1000 steps Run time: 0:00:05.597499 Simulation finished
# fig = plt.figure(figsize=(10, 10))
# ax = fig.add_subplot(111)
# animation = ap.animate(model, fig, ax, animation_plot_single)
# IPython.display.HTML(animation.to_jshtml(fps=20))
animation_plot(AvenueModel, parameters)
WINNER: 3, TIME ON: 0 [2, 2, 2, 0]
/Users/nacho/opt/anaconda3/lib/python3.9/site-packages/numpy/lib/function_base.py:380: RuntimeWarning: Mean of empty slice. avg = a.mean(axis) /Users/nacho/opt/anaconda3/lib/python3.9/site-packages/numpy/core/_methods.py:188: RuntimeWarning: invalid value encountered in double_scalars ret = ret.dtype.type(ret / rcount)
WINNER: 2, TIME ON: 0 [2, 2, 0, 2] WINNER: 3, TIME ON: 10.09999999999998 [2, 2, 2, 0] WINNER: 1, TIME ON: 0 [2, 0, 2, 2] WINNER: 0, TIME ON: 0 [0, 2, 2, 2] WINNER: 2, TIME ON: 10.09999999999998 [2, 2, 0, 2] WINNER: 3, TIME ON: 20.200000000000017 [2, 2, 2, 0]
data = {"avg_speed": [], "cars_red": [], "time": []}
data["avg_speed"].append(results.reporters['Avg Speed'])
data["time"].append(results.reporters['Time'])
Velocidad promedio
time = np.arange(0, data['time'][0][0], 2)
x = np.append(time, [2002])
y = data['avg_speed'][0][0]
fig, ax = plt.subplots()
ax.plot(x, y)
plt.xlabel('Tiempo')
plt.ylabel('Velocidad')
plt.title('Velocidad promedio en semáforo')
plt.show()
Número de autos en semáforo rojo
parameters = [
{
'step_time': 0.1, # Tiempo por cada frame de simulación
'size': 1000, # Tamaño en metros de la avenida
'green': 10, # Duración de la luz verde
'yellow': 5, # Duración de la luz amarilla
'red': 10, # Duración de la luz roja
'cars': 20, # Número de autos en la simulación
'steps': 1000, # Número de pasos de la simulación
},
{
'step_time': 0.1, # Tiempo por cada frame de simulación
'size': 1000, # Tamaño en metros de la avenida
'green': 10, # Duración de la luz verde
'yellow': 5, # Duración de la luz amarilla
'red': 10, # Duración de la luz roja
'cars': 10, # Número de autos en la simulación
'steps': 1000, # Número de pasos de la simulación
},
{
'step_time': 0.1, # Tiempo por cada frame de simulación
'size': 1000, # Tamaño en metros de la avenida
'green': 10, # Duración de la luz verde
'yellow': 5, # Duración de la luz amarilla
'red': 10, # Duración de la luz roja
'cars': 30, # Número de autos en la simulación
'steps': 1000, # Número de pasos de la simulación
},
]
for p in parameters:
model = AvenueModel(p)
results = model.run()
data["cars_red"].append(results.reporters['Cars in red light'])
/Users/nacho/opt/anaconda3/lib/python3.9/site-packages/numpy/lib/function_base.py:380: RuntimeWarning: Mean of empty slice. avg = a.mean(axis) /Users/nacho/opt/anaconda3/lib/python3.9/site-packages/numpy/core/_methods.py:188: RuntimeWarning: invalid value encountered in double_scalars ret = ret.dtype.type(ret / rcount)
WINNER: 0, TIME ON: 0 [0, 2, 2, 2] Completed: 152 stepsWINNER: 0, TIME ON: 10.09999999999998 [0, 2, 2, 2] Completed: 304 stepsWINNER: 0, TIME ON: 20.200000000000017 [0, 2, 2, 2] Completed: 456 stepsWINNER: 3, TIME ON: 0 [2, 2, 2, 0] Completed: 608 stepsWINNER: 3, TIME ON: 10.09999999999998 [2, 2, 2, 0] Completed: 760 stepsWINNER: 2, TIME ON: 0 [2, 2, 0, 2] Completed: 912 stepsWINNER: 0, TIME ON: 30.30000000000016 [0, 2, 2, 2] Completed: 1000 steps Run time: 0:00:06.250175 Simulation finished WINNER: 0, TIME ON: 0 [0, 2, 2, 2] Completed: 152 stepsWINNER: 1, TIME ON: 0 [2, 0, 2, 2] Completed: 304 stepsWINNER: 0, TIME ON: 10.09999999999998 [0, 2, 2, 2] Completed: 456 stepsWINNER: 3, TIME ON: 0 [2, 2, 2, 0] Completed: 608 stepsWINNER: 1, TIME ON: 10.09999999999998 [2, 0, 2, 2] Completed: 760 stepsWINNER: 2, TIME ON: 0 [2, 2, 0, 2] Completed: 912 stepsWINNER: 0, TIME ON: 20.200000000000017 [0, 2, 2, 2] Completed: 1000 steps Run time: 0:00:02.939043 Simulation finished WINNER: 3, TIME ON: 0 [2, 2, 2, 0] Completed: 152 stepsWINNER: 2, TIME ON: 0 [2, 2, 0, 2] Completed: 304 stepsWINNER: 2, TIME ON: 10.09999999999998 [2, 2, 0, 2] Completed: 456 stepsWINNER: 0, TIME ON: 0 [0, 2, 2, 2] Completed: 608 stepsWINNER: 1, TIME ON: 0 [2, 0, 2, 2] Completed: 760 stepsWINNER: 0, TIME ON: 10.09999999999998 [0, 2, 2, 2] Completed: 912 stepsWINNER: 3, TIME ON: 10.09999999999998 [2, 2, 2, 0] Completed: 1000 steps Run time: 0:00:10.672232 Simulation finished
x = list(range(30))
y = data["cars_red"]
print(data["cars_red"])
fig, ax = plt.subplots()
ax.hist(y)
ax.set_xlabel('No. de carros')
ax.set_ylabel('#')
plt.show()
[0 0 Name: Cars in red light, dtype: int64, 0 0 Name: Cars in red light, dtype: int64, 0 0 Name: Cars in red light, dtype: int64]